package com.turing.post.thirdinterface.impl;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.charset.Charset;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import com.turing.post.cardmanagement.util.AppManagement;
import com.turing.post.thirdinterface.util.ThirdInterfaceApplicationException;
import com.turing.post.thirdinterface.util.ThirdInterfaceRespCode;
import com.turing.post.util.PCPSApplicationException;
import com.turing.post.util.PCPSUtil;

/**
 * 三环联机
 * @author ZXL
 *
 */
public class SanHuanSocketOnline {
	
	/**
	 * 控制Socket连接时间
	 * @param bm
	 * @param br
	 * @return
	 * @throws PCPSApplicationException
	 */
	public SanHuanRequest SanHuanControlConnectTime(final AppManagement am, final SanHuanResponse shr)
			throws PCPSApplicationException{
		final ExecutorService exec = Executors.newFixedThreadPool(1);
		SanHuanRequest shRequest = null;
		Callable<SanHuanRequest> call = new Callable<SanHuanRequest>() {   
			public SanHuanRequest call()  throws PCPSApplicationException {   
				return SanHuanAssocTransaction(am,shr);   
			}   
		};
		Future<SanHuanRequest> future = exec.submit(call);   
		try {
			shRequest = future.get(1000 * 30, TimeUnit.MILLISECONDS); //任务处理超时时间设为 30秒 
		} catch (TimeoutException e) {
			 throw new PCPSApplicationException(ThirdInterfaceRespCode.RC_SOCKET, 
	 					"三环联机超时!");
		} catch (Exception e) {
			 throw new PCPSApplicationException(ThirdInterfaceRespCode.RC_SOCKET, 
	 					"三环联机异常!");
		}
		 // 关闭线程池   
		exec.shutdown();
		return shRequest;
	}
	
	/**
	 * 三环联机Socket
	 * @param bm
	 * @param br
	 * @return
	 * @throws PCPSApplicationException
	 */
	private SanHuanRequest SanHuanAssocTransaction(AppManagement am,SanHuanResponse shr)
			throws PCPSApplicationException{
		
		//验证参数
		if (am == null || PCPSUtil.isEmpty(am.getServiceAddr()) || 
				shr == null || PCPSUtil.isEmpty(shr.tranCode)){
			throw new ThirdInterfaceApplicationException(
					ThirdInterfaceApplicationException.ERRMSG_NULLPOINTER,
					ThirdInterfaceRespCode.RC_ARGS_NULL, "参数为空!");
		}
		
		Socket socket = null;
		OutputStream netOut = null;
		DataOutputStream socketoutput = null;
		DataInputStream in = null;
		SanHuanRequest shRequest = null;
		//消息长度
		int msgInt = 0;
		byte[] msgLength = new byte[4];
		//消息体
		byte[] msgBody  = null;
		//得到三环服务地址
		String serviceAddr = am.getServiceAddr();
		String[] services = serviceAddr.split(":");
		//验证三环服务地址格式
		if (services == null || services.length < 2 
				|| !PCPSUtil.isNumeric(services[1])){
			throw new ThirdInterfaceApplicationException(
					ThirdInterfaceApplicationException.ERRMSG_NULLPOINTER,
					ThirdInterfaceRespCode.RC_PARAMETER, "服务地址:"+serviceAddr+"格式错误!");
		}
		
        try {
            socket = new Socket(services[0], Integer.parseInt(services[1]));   
            netOut = socket.getOutputStream();
            socketoutput = new DataOutputStream(netOut); 
            in = new DataInputStream(socket.getInputStream());
            byte[] messgeBody  = SanHuanResponse.checkResponseBusinessType(shr);
            //将xml中的UTF-8体会为GBK,再格式化去掉里面的回车
			byte[] messgeBodyFormat = PCPSUtil.replaceBlank(
					new String(messgeBody, Charset.forName(
							SanHuanXmlHelper.XML_CHARSET_GB18030)).
							replaceAll(SanHuanXmlHelper.XML_CHARSET_UTF, 
									SanHuanXmlHelper.XML_CHARSET_GB18030))
									.getBytes(SanHuanXmlHelper.XML_CHARSET_GB18030);
            if (messgeBody == null){
            	throw new ThirdInterfaceApplicationException(
    					ThirdInterfaceApplicationException.ERRMSG_NULLPOINTER,
    					ThirdInterfaceRespCode.RC_PARAMETER, "无此"+shr.tranCode+"业务类型!");
            }
            
            //向服务器端发送消息长度
            socketoutput.write(String.format("%04d", messgeBodyFormat.length).getBytes());   
            //向服务器端发送消息体
            socketoutput.write(messgeBodyFormat);
            
            //得到消息长度
            msgInt = in.read(msgLength);
            //验证消息长度格式
            if (msgInt != 4 || !PCPSUtil.isNumeric(new String(msgLength))){
            	throw new ThirdInterfaceApplicationException(
    					ThirdInterfaceApplicationException.ERRMSG_NULLPOINTER,
    					ThirdInterfaceRespCode.RC_PARAMETER, "得到消息长度:"+new String(msgLength)+"格式错误!");
            }
            msgBody = new byte[Integer.parseInt(new String(msgLength))];
            //得到消息体
            msgInt = in.read(msgBody);
            //验证消息体
            if (msgBody == null || msgInt <= 0){
            	throw new ThirdInterfaceApplicationException(
    					ThirdInterfaceApplicationException.ERRMSG_NULLPOINTER,
    					ThirdInterfaceRespCode.RC_PARAMETER, "得到消息体为空!");
            }
            shRequest = SanHuanRequest.checkRequestBusinessType(shr.tranCode,msgBody);
            if (shRequest == null){
            	throw new ThirdInterfaceApplicationException(
    					ThirdInterfaceApplicationException.ERRMSG_NULLPOINTER,
    					ThirdInterfaceRespCode.RC_PARAMETER, "消息体:"+new String(msgBody)+
    					"解析有误!");
            }
            //验证请求交易码与得到交易码是否一致
            if (!shr.tranCode.equals(shRequest.tranCode)){
            	throw new ThirdInterfaceApplicationException(
    					ThirdInterfaceApplicationException.ERRMSG_NULLPOINTER,
    					ThirdInterfaceRespCode.RC_PARAMETER, "得到交易码:"+shRequest.tranCode+",与请求交易码:"+shr.tranCode+"不一致!");
            }
            socketoutput.close();   
            in.close();  
            socket.close();
            netOut.close();
        } catch (Exception e) {
        	 throw new PCPSApplicationException(ThirdInterfaceRespCode.RC_SOCKET, 
 					"三环联机异常!");
        } finally {   
            if (socket != null) {   
                try {   
                    socket.close();
                    in.close(); 
                    socketoutput.close();
                } catch (IOException e) {   
                	 throw new PCPSApplicationException(ThirdInterfaceRespCode.RC_SOCKET, 
         					"三环联机异常!");
                }   
            }   
        }   
		return shRequest;
	}
}
